package com.ytktt.study.week7.task2;

import com.google.common.collect.Lists;
import com.ytktt.study.week7.task2.dbms.DatabaseConnection;
import com.ytktt.study.week7.task2.entity.OrderInfoEntity;
import com.ytktt.study.week7.task2.gen.id.Snowflake;
import com.ytktt.study.week7.task2.repository.OrderInfoRepository;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.ListUtils;
import org.apache.commons.lang3.StringUtils;

import java.math.BigDecimal;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.List;

/**
 * TODO
 *
 * @author ytk
 */
@Slf4j
public class Application {

    private static final int MAX = 1_000_000;

    public static void main(String[] args) throws SQLException, CloneNotSupportedException {
        Timestamp now = new Timestamp(System.currentTimeMillis());
        Snowflake snowflake = new Snowflake(1L, 1L);
        OrderInfoEntity base = new OrderInfoEntity();
        base.setId(String.valueOf(snowflake.nextId()));
        base.setUserId(1);
        base.setItemId(1);
        base.setItemPrice(new BigDecimal("9.9"));
        base.setAmount(1);
        base.setOrderPrice(new BigDecimal("9.9"));
        base.setDelFlag((byte) 1);
        base.setStatus((byte) 1);
        base.setCreateTime(now);
        base.setUpdateTime(now);

        DatabaseConnection dc = DatabaseConnection.getInstance();
        OrderInfoRepository orderInfoRepository = OrderInfoRepository.getInstance();
        List<OrderInfoEntity> list = Lists.newArrayList();
        for (int i = 0; i < MAX; ++i) {
            OrderInfoEntity clone = (OrderInfoEntity) base.clone();
            clone.setId(String.valueOf(snowflake.nextId()));
            list.add(clone);
        }

//        loopSave(dc, orderInfoRepository, list);
//        batchSave(dc, orderInfoRepository, list);
//        multiValueSave(dc, orderInfoRepository, list);
        groupMultiValueSave(dc, orderInfoRepository, list);
    }

    private static void loopSave(DatabaseConnection dc, OrderInfoRepository repository, List<OrderInfoEntity> list) throws SQLException {
        String sql = "INSERT INTO tb_order_info (id, user_id, item_id, item_price, amount, order_price, del_flag, " +
                "status, create_time, update_time) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
        Connection truncateConnection = dc.getConnection();
        repository.truncate(truncateConnection);
        truncateConnection.commit();
        long startTime = System.currentTimeMillis();
        Connection connection = dc.getConnection();
        repository.loopBatch(list, connection, sql);
        connection.commit();
        log.info("loop save cost : {}ms", System.currentTimeMillis() - startTime);
    }

    private static void batchSave(DatabaseConnection dc, OrderInfoRepository repository, List<OrderInfoEntity> list) throws SQLException {
        String sql = "INSERT INTO tb_order_info (id, user_id, item_id, item_price, amount, order_price, del_flag, " +
                "status, create_time, update_time) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
        Connection truncateConnection = dc.getConnection();
        repository.truncate(truncateConnection);
        truncateConnection.commit();
        long startTime = System.currentTimeMillis();
        Connection connection = dc.getConnection();
        repository.saveBatch(list, connection, sql);
        connection.commit();
        log.info("batch save cost : {}ms", System.currentTimeMillis() - startTime);
    }

    private static void multiValueSave(DatabaseConnection dc, OrderInfoRepository repository, List<OrderInfoEntity> list) throws SQLException {
        String sql = "INSERT INTO tb_order_info (id, user_id, item_id, item_price, amount, order_price, del_flag, " +
                "status, create_time, update_time) VALUES ";
        String placeHolder = "(?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
        List<String> placeHolderList = Lists.newArrayListWithExpectedSize(MAX);
        for (int i = 0; i < MAX; ++i) {
            placeHolderList.add(placeHolder);
        }
        sql = sql + StringUtils.join(placeHolderList, ',');
        Connection truncateConnection = dc.getConnection();
        repository.truncate(truncateConnection);
        truncateConnection.commit();
        long startTime = System.currentTimeMillis();
        Connection connection = dc.getConnection();
        repository.multiValueSave(list, connection, sql);
        connection.commit();
        log.info("multi value save cost : {}ms", System.currentTimeMillis() - startTime);
    }

    private static void groupMultiValueSave(DatabaseConnection dc, OrderInfoRepository repository, List<OrderInfoEntity> list) throws SQLException {
        int groupSize = 400;
        String sql = "INSERT INTO tb_order_info (id, user_id, item_id, item_price, amount, order_price, del_flag, " +
                "status, create_time, update_time) VALUES ";
        String placeHolder = "(?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
        List<String> placeHolderList = Lists.newArrayListWithExpectedSize(groupSize);
        for (int i = 0; i < groupSize; ++i) {
            placeHolderList.add(placeHolder);
        }
        sql = sql + StringUtils.join(placeHolderList, ',');
        Connection truncateConnection = dc.getConnection();
        repository.truncate(truncateConnection);
        truncateConnection.commit();
        long startTime = System.currentTimeMillis();
        Connection connection = dc.getConnection();
        List<List<OrderInfoEntity>> partition = ListUtils.partition(list, groupSize);
        for (List<OrderInfoEntity> partList : partition) {
            repository.multiValueSave(partList, connection, sql);
        }
        connection.commit();
        log.info("group multi value save cost : {}ms", System.currentTimeMillis() - startTime);
    }
}
